package com.myk.game.gobangchess.rooms;

import com.myk.game.gobangchess.CustomBottom;
import com.myk.game.gobangchess.Sign;
import com.myk.game.gobangchess.constants.ColorCost;
import com.myk.game.gobangchess.constants.WinMode;
import com.myk.game.gobangchess.rooms.absrooms.AbsDiffViewChessRoom;
import com.myk.game.gobangchess.rooms.absrooms.movechess.MoreColorCost;
import com.myk.game.gobangchess.signs.*;
import com.myk.game.gobangchess.utils.GridsUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 飞王棋
 * 相关资料 https://tieba.baidu.com/p/3316123555?red_tag=2437207192
 */
public class FlyKingRoom extends AbsDiffViewChessRoom {

    private final static String COLOR_BLACK_CHESS_TEXT = "#FFEE6666"; //黑棋的文字颜色红色
    private final static String COLOR_WHITE_CHESS_TEXT = "#FF6666EE"; //白棋的文字颜色蓝色
    private final static String COLOR_GRAY_CHESS_TEXT = "#FFEEEE66"; //公共棋子的文字颜色黄色
    private CacheSign chessBoardCacheSign; //背景缓存标记
    private final List<int[]> moveArrayList = new ArrayList<>(); // 棋子移动标记
    private Integer putPoint = null; //打入落子标记
    private Chess lastMoveChess; //上回合移动的棋子
    private final List<Integer> afferentChessLink = new ArrayList<>(); //当前传入链，当前回合进入该链的棋子不能再进入了
    private List<Chess> chessList; //场上棋子集合
    private List<Chess> captiveList; //公共棋台棋子集合
    private Sider blackSider; //游戏黑方实体
    private Sider whiteSider; //游戏白方实体

    public FlyKingRoom(String roomName) {
        super(roomName, "日出在新棋吧设计的传棋，别看名字朴素，游戏创意是很独特。", "飞王棋", GridsUtils.createEmptyGrids(9, 8), true, true);
        initChessBoardCacheSign();
    }

    //棋盘背景的设计
    private void initChessBoardCacheSign() {
        List<Sign> chessboardStyle = new ArrayList<>();
        int row = curGrids.length;
        int col = curGrids[0].length;
        //绘制类似国际象棋的黑白相间的格子
        List<Integer> bGrids = new ArrayList<>();
        List<Integer> wGrids = new ArrayList<>();
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                int index = getIndex(i, j);
                if ((i + j) % 2 == 0) {
                    bGrids.add(index);
                }
                else {
                    wGrids.add(index);
                }
            }
        }
        chessboardStyle.add(new ColorSign(bGrids, "#FF888888"));
        chessboardStyle.add(new ColorSign(wGrids, "#FFDDDDDD"));
        //画棕色外边框
        chessboardStyle.add(new GroundSign(getIndex(0, 0), getIndex(row-1, col-1), "#00000000", "#FFAA6622", 2.2f, 0, 0));
        //将背景封装为缓存标记
        chessBoardCacheSign = new CacheSign(this,"chessBoardCacheSign",4,true,chessboardStyle); //*** 修改背景样式记得改这里的版本号！！！
    }

    @Override
    public CacheSign getCacheSignByName(String cacheName) {
        return chessBoardCacheSign;
    }

    @Override
    public String getRuleText() {
        return "《飞王棋》\n" +
                "【来源介绍】：\n" +
                "日出在新棋吧设计的《传棋》，创造性的将落子棋和移子棋的机制结合起来，最初宣称灵感来自江柯。后来日出没有兴趣继续研究它了，逆界现在把这款棋复刻上来，改名叫《飞王棋》，规则也会有一定的调整。\n" +
                "\n" +
                "【游戏规则】：" +
                "黑白双方各有1枚专用棋子，“王”。\n" +
                "双方共有24枚公用棋子，”车“、”马“、”炮“、”象“、”兵“、”士“，各4枚。\n" +
                "\n" +
                "【棋子走法】:\n" +
                "兵：直向走一空格。\n" +
                "士：斜向走一空格。\n" +
                "马：斜向走一比二空格，国际象棋马的走法。\n" +
                "车：直向走任意空格。\n" +
                "象：斜向走任意空格。\n" +
                "炮：八方向跨越一个棋子后走任意空格。\n" +
                "王：八方向走一格，只有王可以走到其它棋子之上，走到对方王之上可以吃掉获胜，走到公共棋子之上可以进行”飞王“移动。\n" +
                "飞王：本方王走到公共棋子之上，接着可以用被踩踏的棋子的走子法飞到另一格，如果再次飞到另一个公共棋子之上还能继续连锁飞王，直到落在空格处或者对方王所在格。\n" +
                "\n" +
                "【玩家行动】：\n" +
                "每步棋可以从以下三种行动方式中选择其一：\n" +
                "1、从公共棋台上选择一个公共棋子落入棋盘上。\n" +
                "2、选择场上一个公共棋子移动。\n" +
                "3、移动己方的王。\n" +
                "\n" +
                "【禁手】：\n" +
                "1、不得移动对方刚移动过的公共棋子。\n" +
                "2、不得移动对方刚刚放入的公共棋子。\n" +
                "3、王不得走到对方刚刚放入的公共棋子之上。\n" +
                "4、王不得待机不动，也不得以飞王方式最终返回出发点。\n" +
                "\n" +
                "【胜负方式】\n" +
                "只有王之间可以互吃，其它任何情况都不能吃子，吃掉对方的王就赢了。";
    }

    @Override
    public int getCountdownSec() {
        return 180; //思考时间比较长，改成300s吧
    }

    @Override
    public String getGameInfo(int viewPoint) {
        //先清空棋盘
        signList.clear();
        //三种身份各自视角的自定义绘制
        if (viewPoint == 1) {
            blackSider.render();
        }
        else if (viewPoint == 2) {
            whiteSider.render();
        }
        else {
            publicRender();
        }
        return super.getGameInfo();
    }

    //公共渲染
    public void publicRender() {
        //画棋盘背景
        signList.add(chessBoardCacheSign);
        //绘制场上棋子
        renderChessList();
        //绘制双方的公共棋子预览
        renderCaptiveListPreview();
        //绘制移动箭头
        renderMoveArray();
        //绘制打入落子标记
        renderPutPoint();
    }

    //遍历绘制场上棋子
    public void renderChessList() {
        curGrids = GridsUtils.copyGrids(originGrids);
        if (chessList != null) {
            for (Chess piece : chessList) {
                if (piece.side == 1){
                    curGrids[piece.row][piece.col] = 11; //显示棋子的底座
                    signList.add(new TextSign(piece.getIndex(), piece.name, COLOR_BLACK_CHESS_TEXT)); //绘制棋子外观
                }
                else if (piece.side == 2){
                    curGrids[piece.row][piece.col] = 12; //显示棋子的底座
                    signList.add(new TextSign(piece.getIndex(), piece.name, COLOR_WHITE_CHESS_TEXT)); //绘制棋子外观
                }
                else {
                    curGrids[piece.row][piece.col] = 7; //显示棋子的底座
                    signList.add(new TextSign(piece.getIndex(), piece.name, COLOR_GRAY_CHESS_TEXT)); //绘制棋子外观
                }
            }
        }
    }

    //绘制双方公共棋子预览
    public void renderCaptiveListPreview() {
        if (blackSider != null && whiteSider != null) {
            float leftX = 1+(0.3f)/curGrids[0].length; //左列位置 棋盘终点再偏移3/10单位格子
            float rightX = 1+(0.7f)/curGrids[0].length; //右列位置 棋盘终点再偏移7/10单位格子
            float blackTop = (1.75f) / curGrids.length; //黑方预览顶部位置
            float paddingY = 0.0155f / curGrids.length; //因为预览棋子底座和文字大小不同，所以需要做padding，让文字正好显示在底座中心
            float unitH = 0.5f / curGrids.length; //行距定为半个格子
            for (int i = 0; i < captiveList.size(); i++) {
                int j = i/2; //形成书写文字的排列效果每行两列
                float bClipY = blackTop + j * unitH;
                signList.add(new TitleSign(i % 2 == 0?leftX:rightX, bClipY, 0, "●", ColorCost.GRAY, 0.35f));
                signList.add(new TitleSign(i % 2 == 0?leftX:rightX, bClipY  + paddingY , 0, captiveList.get(i).name, COLOR_GRAY_CHESS_TEXT, 0.25f));
            }
        }
    }

    //绘制移动箭头
    public void renderMoveArray() {
        for (int[] moveArray : moveArrayList) {
            signList.add(new LineSign(moveArray[0], moveArray[1], MoreColorCost.MOVE, 1));
        }
    }

    //绘制打入落子标记
    private void renderPutPoint() {
        if (putPoint != null){
            signList.add(new GroundSign(putPoint, "#00000000", ColorCost.NEW_PUT_POINT_LIGHT, 1.0f, 0, 0)); //淡绿色新落子选框标记
            signList.add(new BadgeSign(putPoint,"◬",8,ColorCost.RED_TEXT,ColorCost.TRANSPARENT)); //禁止传入落子标记
        }
    }

    @Override
    public void resetGrids() {
        super.resetGrids();
        moveArrayList.clear();
        afferentChessLink.clear();
        putPoint = null;
        lastMoveChess = null;
        chessList = null;
        blackSider = null;
        whiteSider = null;
    }

    @Override
    protected void onStartPrepare() {
        //初始化对弈双方状态
        blackSider = new Sider(this, 1,new General(this));
        whiteSider = new Sider(this, 2,new General(this));
        //初始化场上棋子
        chessList = new ArrayList<>();
        chessList.add(blackSider.king);
        chessList.add(whiteSider.king);
        //初始化公共棋台棋子
        captiveList = new ArrayList<>();
        // 兵
        captiveList.add(new Pawn(this));
        captiveList.add(new Pawn(this));
        captiveList.add(new Pawn(this));
        captiveList.add(new Pawn(this));
        // 炮
        captiveList.add(new Cannon(this));
        captiveList.add(new Cannon(this));
        captiveList.add(new Cannon(this));
        captiveList.add(new Cannon(this));
        // 车
        captiveList.add(new Chariot(this));
        captiveList.add(new Chariot(this));
        captiveList.add(new Chariot(this));
        captiveList.add(new Chariot(this));
        // 马
        captiveList.add(new Horse(this));
        captiveList.add(new Horse(this));
        captiveList.add(new Horse(this));
        captiveList.add(new Horse(this));
        // 象
        captiveList.add(new Bishop(this));
        captiveList.add(new Bishop(this));
        captiveList.add(new Bishop(this));
        captiveList.add(new Bishop(this));
        // 士
        captiveList.add(new Guard(this));
        captiveList.add(new Guard(this));
        captiveList.add(new Guard(this));
        captiveList.add(new Guard(this));
        noticeBlackMove(); //默认通知黑方先行动
    }

    @Override
    protected void prepareInGameButtons() {
        //绑定切换棋台按钮
        if (player_black != player_white) {
            player_black.registerCustomBottom(new CustomBottom(this, "切换棋台", p -> blackSider.switchPlat()));
            player_white.registerCustomBottom(new CustomBottom(this, "切换棋台", p -> whiteSider.switchPlat()));
        }
        else {
            player_black.registerCustomBottom(new CustomBottom(this, "切换棋台", p -> {
                if (cur == 1) blackSider.switchPlat();
                else if (cur == 2) whiteSider.switchPlat();
            }));
        }
    }

    @Override
    public void doRule(int row, int col, int value) {
        if (value == 1) {
            blackSider.doRule(row, col);
        }
        else if (value == 2) {
            whiteSider.doRule(row, col);
        }
    }

    //检测胜负
    public void checkOver() {
        //增加步数
        stepAdd();
        //胜负判断有点复杂，暂时只判断是否吃掉对方的帅
        if (!chessList.contains(whiteSider.king)) {
            doOver(WinMode.BLACK_WIN, "黑方获胜！");
            return;
        }
        else if (!chessList.contains(blackSider.king)) {
            doOver(WinMode.WHITE_WIN, "白方获胜！");
            return;
        }
        //++王无棋可走判负（暂时没有发现有能困毙的情况，暂时不加这个判断）
        //++出现按fide规则定义的第三次重复局面 不判和 但判负，二次的时候就gameTip提示了
        changeNoticeMove();//切换行动方
    }

    //切换行动方
    public void changeNoticeMove() {
        if (cur == 1) {
            noticeWhiteMove();
        }
        else {
            noticeBlackMove();
        }
    }

    //根据坐标搜索棋子 （有多个棋子时取城门之上的棋子, 可为空）
    public Chess getChessByPos(int row, int col) {
        for (Chess chess : chessList) {
            if (chess.row == row && chess.col == col) {
                return chess;
            }
        }
        return null;
    }

    //根据index搜索棋子 （有多个棋子时取城门之上的棋子, 可为空）
    public Chess getChessByIndex(int index) {
        for (Chess chess : chessList) {
            if (chess.getIndex() == index) {
                return chess;
            }
        }
        return null;
    }

    //检查传入的棋子是否可传入
    private boolean checkAfferentAble(Chess chess) {
        //上回合对方新打入的棋子不能传入
        if (putPoint != null && chess.getIndex() == putPoint){
            return false;
        }
        //本回合已经传入过的棋子不能传入（这条不写入到规则文本中，因为没有意义，但是保留在这里为了美化交互效果）
        if (afferentChessLink.contains(chess.getIndex())){
            return false;
        }
        return true;
    }

    /**
     * 对弈双方的各种信息
     */
    private static class Sider {

        public FlyKingRoom room;
        private final int side;//归属黑棋还是白棋 1黑  2白
        private boolean isOpenPlat; //是否展开了棋台显示
        private Chess king; //棋盘上的王
        private Chess choose; //当前选中的场上棋子
        private Chess captive; //当前选中的持棋棋子
        private Chess transfer; //当前选中的传送台

        public Sider(FlyKingRoom room, int side,Chess king) {
            this.room = room;
            this.side = side;
            this.king = king;
            if (side == 1){
                this.king.side = 1;
                this.king.row = 1;
                this.king.col = 2;
            }
            else {
                this.king.side = 2;
                this.king.row = 7;
                this.king.col = 5;
            }
        }

        //私有独立界面渲染
        public void render() {
            //棋台打开状态显示棋台
            if (isOpenPlat) {
                //画棋台相关私有画面
                renderDetentionPlat();
                //绘制双方的公共棋子预览
                room.renderCaptiveListPreview();
            }
            //棋台关闭状态显示棋盘
            else {
                //画棋盘背景、场上棋子、公共棋子预览、移动路径等公共画面
                room.publicRender();
                //场上棋子选中效果等私有画面
                if (choose != null) {
                    renderChessChoose();
                    if (transfer != null){
                        renderTransferChoose();
                    }
                }
                else if (captive != null){
                    renderCaptiveChoose();
                }
            }
        }

        //棋台的绘制
        private void renderDetentionPlat() {
            //画公共棋台标题
            room.signList.add(new GroundSign(room.getIndex(1, 2), room.getIndex(1, 5), "#FFAA6622", "#FFAA6622", 2.5f, 0, 0));
            room.signList.add(new TitleSign(0.5f, 0.15f, 0, "公共棋台", "#FF444444", 0.8f));
            //画公共棋台边框
            room.signList.add(new GroundSign(room.getIndex(2, 2), room.getIndex(7, 5), "#FFC9C2A7", "#FFAA6622", 2.5f, 0, 0));
            //遍历绘制棋台棋子
            room.curGrids = GridsUtils.copyGrids(room.originGrids);
            for (int i = 0; i < room.captiveList.size(); i++) {
                Chess chess = room.captiveList.get(i);
                //棋子绘制的位置根据在captiveList中的位置来
                int cR = (i / 4) + 2;
                int cC = i % 4 + 2;
                room.curGrids[cR][cC] = 7; //显示棋子的底座
                chess.row = cR; //正常不该在这里修改棋子状态的，但是可以解决选中公共棋子时根据坐标逆运算棋子索引的代码，并且我确保这里不会导致其它bug
                chess.col = cC;
                room.signList.add(new TextSign(room.getIndex(cR, cC), chess.name, room.COLOR_GRAY_CHESS_TEXT)); //绘制棋子外观
                //画棋台持棋棋子选中效果
                if (captive != null && captive == chess) {
                    room.signList.add(new GroundSign(room.getIndex(cR, cC), "#00FFFFFF", "#FF33CC33", 2F, 0, 1));
                }
            }
        }

        //当前选中棋子的绘制
        private void renderChessChoose() {
            //未选取传送台时
            if (transfer == null){
                //画选中绿框
                room.signList.add(new GroundSign(choose.getIndex(), "#00FFFFFF", "#FF33CC33", 2F, 0, 1));
                //画一下可移动范围
                for (Integer index : choose.getMoveRange()) {
                    room.signList.add(new ColorSign(index, MoreColorCost.MOVE));
                }
                //画一下吃子范围
                for (Integer index : choose.getEatRange()) {
                    room.signList.add(new ColorSign(index, MoreColorCost.EAT));
                }
                //画一下可选传送台的范围
                for (Integer index : choose.getTransferRange()) {
                    room.signList.add(new ColorSign(index, MoreColorCost.MOVE));
                }
            }
            //选择了传送台时
            else {
                //选中棋子原位置禁止传入
                room.signList.add(new ColorSign(choose.getIndex(), "#66EE6666"));
                room.signList.add(new TextSign(choose.getIndex(),"◬",ColorCost.RED_TEXT));
                //选中棋子以角标形式显示在传送台上
                room.signList.add(new BadgeSign(transfer.getIndex(), choose.name, 2, choose.side==1?COLOR_BLACK_CHESS_TEXT:COLOR_WHITE_CHESS_TEXT, choose.side==1?ColorCost.BLACK:ColorCost.WHITE));
                //绘制可选的传入位置
                for (Integer index : transfer.getAfferentRange(choose)) {
                    room.signList.add(new ColorSign(index, MoreColorCost.MOVE));
                }
            }
        }

        //当前传入状态预览
        private void renderTransferChoose() {
            //绘制连线
            room.signList.add(new LineSign(choose.getIndex(),room.afferentChessLink.get(0),ColorCost.MOVE_ARROW_LIGHT,1)); //程序逻辑确保了transfer不为null时choose肯定不为空，afferentChessLink也肯定有一个值
            for (int i = 0; i < room.afferentChessLink.size() - 1; i++) {
                Integer index = room.afferentChessLink.get(i);
                //禁止传入落子标记
                room.signList.add(new BadgeSign(index,"◬",8,ColorCost.RED_TEXT,ColorCost.TRANSPARENT));
                //绘制连线
                room.signList.add(new LineSign(index,room.afferentChessLink.get(i+1),ColorCost.MOVE_ARROW_LIGHT,1));
            }
        }

        //当前选中公共棋子棋子的绘制
        private void renderCaptiveChoose() {
            //待选打入点的绘制-全盘的空格
            for (int i = 0; i < room.curGrids.length; i++) {
                for (int j = 0; j < room.curGrids[0].length; j++) {
                    if (room.curGrids[i][j] == 0){
                        room.signList.add(new ColorSign(room.getIndex(i, j), MoreColorCost.MOVE));
                    }
                }
            }

            //公共棋子预览的位置加个提示点
            float leftX = 1+(0.3f)/room.curGrids[0].length; //左列位置 棋盘终点再偏移3/10单位格子
            float rightX = 1+(0.7f)/room.curGrids[0].length; //右列位置 棋盘终点再偏移7/10单位格子
            float blackTop = (1.75f) / room.curGrids.length; //黑方预览顶部位置
            float paddingY = 0.0155f / room.curGrids.length; //因为预览棋子底座和文字大小不同，所以需要做padding，让文字正好显示在底座中心
            float unitH = 0.5f / room.curGrids.length; //行距定为半个格子
            for (int i = 0; i < room.captiveList.size(); i++) {
                int j = i/2; //形成书写文字的排列效果每行两列
                float bClipY = blackTop + j * unitH;
                if (room.captiveList.get(i) == captive){
                    room.signList.add(new TitleSign(i % 2 == 0?leftX:rightX, bClipY, 0, "▢",  ColorCost.NEW_PUT_POINT_LIGHT, 0.35f));
                    room.signList.add(new TitleSign(i % 2 == 0?leftX:rightX, bClipY  + paddingY , 0, room.captiveList.get(i).name, MoreColorCost.MOVE, 0.25f));
                }
            }
        }

        //切换棋台显示
        public void switchPlat() {
            this.isOpenPlat = !isOpenPlat;
            room.noticeAllRefreshGameInfo();
        }

        //私有独立交互逻辑处理
        public void doRule(int row, int col) {
            //在公共棋台上点击
            if (isOpenPlat) {
                Chess chess = getByCaptiveList(row, col);
                if (chess != null) chooseCaptive(chess);
            }
            //在棋盘上点击
            else {
                //已选中场上棋子时
                if (choose != null) {
                    //已选中传入底座时
                    if (transfer != null) {
                        if (transfer.getAfferentRange(choose).contains(room.getIndex(row, col))) {
                            afferentChess(row, col); //初次传入棋子
                        }
                        else {
                            cancelTransfer(); //取消传入底座的选取
                        }
                    }
                    //未选择传入时
                    else {
                        Chess newChess = room.getChessByPos(row, col);
                        //再点击空格
                        if (newChess == null) {
                            if (choose.getMoveRange().contains(room.getIndex(row, col))) {
                                moveChess(row, col); //移动选中棋子
                            }
                            else {
                                cancelChoose(); //取消选中棋子
                            }
                        }
                        //再点击对方王时
                        else if (newChess instanceof General){
                            if (choose.getEatRange().contains(newChess.getIndex())) {
                                eatChess(newChess); //吃掉对方棋子
                            }
                            else {
                                cancelChoose(); //取消选中棋子
                            }
                        }
                        //再点击公共棋子时
                        else {
                            if (choose.getTransferRange().contains(newChess.getIndex())) {
                                chooseTransfer(newChess); //选中传入底座//只有王的getTransferRange()才会有数据
                            }
                            else if (room.putPoint!=null && newChess.getIndex() == room.putPoint){
                                cancelChoose(); //点击对方刚置入场上的棋子时，取消选中棋子
                            }
                            else if (room.lastMoveChess != null && newChess == room.lastMoveChess){
                                cancelChoose(); //点击对方刚移动的棋子时，取消选中棋子
                            }
                            else {
                                chooseChess(newChess); //另选其它己方棋子
                            }
                        }
                    }
                }
                //已选中公共棋台的棋子时
                else if (captive != null) {
                    if (room.curGrids[row][col] == 0){
                        putChess(row, col);
                    }
                    else {
                        cancelCaptive();
                    }
                }
                //未选中任何棋子时
                else {
                    Chess chess = room.getChessByPos(row, col);
                    if (chess == null) return; //不能选中空格
                    if (chess instanceof General && chess.side != side) return; //不能选中对方王
                    if (room.putPoint!=null && chess.getIndex() == room.putPoint) return; //不能选中对方刚打入的棋子
                    if (room.lastMoveChess != null && chess == room.lastMoveChess) return;//不能选中对方刚移动的棋子
                    chooseChess(chess); //选中棋子
                }
            }
        }

        //获取当前位置的公共棋子棋子
        public Chess getByCaptiveList(int row, int col) {
            for (Chess chess : room.captiveList) {
                if (chess.getIndex() == room.getIndex(row, col)) {
                    return chess;
                }
            }
            return null;
        }

        //选中棋子
        private void chooseChess(Chess choose) {
            this.captive = null;
            this.transfer = null;
            this.choose = choose;
            room.noticeAllRefreshGameInfo();
        }

        //取消场上棋子的选中
        private void cancelChoose() {
            this.transfer = null;
            this.choose = null;
            room.noticeAllRefreshGameInfo();
        }

        //选中公共棋子
        private void chooseCaptive(Chess captive) {
            if (this.transfer != null){
                cancelTransfer();
            }
            this.choose = null;
            this.transfer = null;
            this.captive = captive;
            switchPlat();
        }

        //取消公共棋子的选中
        private void cancelCaptive() {
            this.transfer = null;
            this.captive = null;
            room.noticeAllRefreshGameInfo();
        }

        //选中传入台
        private void chooseTransfer(Chess transfer) {
            this.transfer = transfer;
            room.afferentChessLink.clear(); //重置当前传入链
            room.afferentChessLink.add(transfer.getIndex()); //添加首个传入结点到传入链
            room.chessList.remove(choose); //传入棋子临时从场上离开（放到传送台的上面）
            room.noticeAllRefreshGameInfo();
        }

        //取消传入台的选中
        private void cancelTransfer() {
            this.transfer = null;
            room.afferentChessLink.clear(); //清空当前传入链
            room.chessList.add(choose); //传入棋子从传送台上还原到场上
            room.noticeAllRefreshGameInfo();
        }

        //移动棋子
        private void moveChess(int row, int col) {
            //更新移动标记
            room.moveArrayList.clear();
            room.moveArrayList.add(new int[]{choose.getIndex(), room.getIndex(row, col)});
            room.afferentChessLink.clear();
            room.putPoint = null;
            room.lastMoveChess = choose;
            //更新棋子坐标
            choose.row = row;
            choose.col = col;
            //移动过后选中状态取消
            choose = null;
            //检查回合是否结束（切换行动方）
            room.checkOver();
        }

        //吃掉棋子
        private void eatChess(Chess target) {
            //更新移动标记
            room.moveArrayList.clear();
            room.moveArrayList.add(new int[]{choose.getIndex(), target.getIndex()});
            room.afferentChessLink.clear();
            room.putPoint = null;
            room.lastMoveChess = choose;
            //被吃棋子移到棋台
            room.chessList.remove(target);
            room.captiveList.add(target);
            //更新棋子坐标
            choose.row = target.row;
            choose.col = target.col;
            //移动过后选中状态取消
            choose = null;
            //检查回合是否结束（切换行动方）
            room.checkOver();
        }

        //传入棋子
        private void afferentChess(int row, int col) {
            room.afferentChessLink.add(room.getIndex(row, col));  //添加传入链节点
            Chess chess = room.getChessByPos(row, col);
            if (chess == null) {
                afferentToSpace(row,col); //传入到空位
            }
            else if (chess instanceof General) {
                afferentToKing(chess); //传入到对方王上
            }
            else {
                afferentOnChess(chess);//传入到另一个棋子上
            }
        }

        //传入棋子到空位
        private void afferentToSpace(int row, int col) {
            //更新移动标记
            room.moveArrayList.clear();
            room.moveArrayList.add(new int[]{choose.getIndex(), room.afferentChessLink.get(0)});
            for (int i = 0; i < room.afferentChessLink.size() - 1; i++) {
                Integer from = room.afferentChessLink.get(i);
                Integer to = room.afferentChessLink.get(i + 1);
                room.moveArrayList.add(new int[]{from, to});
            }
            room.afferentChessLink.clear();
            room.putPoint = null;
            room.lastMoveChess = choose;
            //传入棋子还原到棋盘上
            room.chessList.add(choose);
            //更新棋子坐标
            choose.row = row;
            choose.col = col;
            //传入过后取消选中状态
            transfer = null;
            choose = null;
            //检查回合是否结束（切换行动方）
            room.checkOver();
        }

        //传入棋子到对方王
        private void afferentToKing(Chess kingChess) {
            //更新移动标记
            room.moveArrayList.clear();
            room.moveArrayList.add(new int[]{choose.getIndex(), room.afferentChessLink.get(0)});
            for (int i = 0; i < room.afferentChessLink.size() - 1; i++) {
                Integer from = room.afferentChessLink.get(i);
                Integer to = room.afferentChessLink.get(i + 1);
                room.moveArrayList.add(new int[]{from, to});
            }
            room.afferentChessLink.clear();
            room.putPoint = null;
            room.lastMoveChess = choose;
            //王棋子被吃掉
            room.chessList.remove(kingChess);
            //传入棋子还原到棋盘上
            room.chessList.add(choose);
            //更新棋子坐标
            choose.row = kingChess.row;
            choose.col = kingChess.col;
            //传入过后取消选中状态
            transfer = null;
            choose = null;
            //检查回合是否结束（切换行动方）
            room.checkOver();
        }

        //传入到另一个棋子上
        private void afferentOnChess(Chess chess) {
            //更换传入底座
            transfer = chess;
            //刷新界面，当前玩家继续操作
            room.noticeAllRefreshGameInfo();
        }

        //打入棋子
        private void putChess(int row, int col) {
            //新增落子提示
            room.moveArrayList.clear();
            room.afferentChessLink.clear();
            room.putPoint = room.getIndex(row,col);
            room.lastMoveChess = choose;
            //棋台棋子放到棋盘
            room.captiveList.remove(captive);
            captive.row = row;
            captive.col = col;
            room.chessList.add(captive); //被打入棋子添加到场上
            //打入过后取消选中状态
            transfer = null;
            captive = null;
            //检查回合是否结束（切换行动方）
            room.checkOver();
        }

    }

    /**
     * 棋子公共抽象类
     */
    private abstract static class Chess {

        public FlyKingRoom room;
        public String name;
        public int side;
        public int row;
        public int col;

        public Chess(FlyKingRoom room, String name) {
            this.room = room;
            this.name = name;
        }

        //获取棋子的坐标索引
        public int getIndex() {
            return room.getIndex(row, col);
        }

        //获取自身一周周围的格子（自身为中心“田”区，棋盘范围之外的不加入，最多8个格子）
        protected List<Integer> getAroundRange() {
            int[][] dxdys = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}};
            List<Integer> rangeIndex = new ArrayList<>();
            for (int[] dxdy : dxdys) {
                int x = row + dxdy[0];
                int y = col + dxdy[1];
                if (x >= 0 && x < room.curGrids.length && y >= 0 && y < room.curGrids[0].length && room.curGrids[x][y] == 0) {
                    rangeIndex.add(room.getIndex(x, y));
                }
            }
            return rangeIndex;
        }

        //根据规则搜索棋子默认的移动范围
        protected List<Integer> defMoveRange(int[][] dxdys, int distance) {
            return defMoveRange(dxdys, distance, 0, 0);
        }

        //根据规则搜索棋子默认的移动范围
        protected List<Integer> defMoveRange(int[][] dxdys, int distance, int canJump, int mustJump) {
            List<Integer> rangeIndex = new ArrayList<>();
            for (int[] dxdy : dxdys) {
                int skip = 0;
                for (int x = row + dxdy[0], y = col + dxdy[1], i = 0; x >= 0 && x < room.curGrids.length && y >= 0 && y < room.curGrids[0].length && i < distance; x += dxdy[0], y += dxdy[1], i++) {
                    Chess chess = room.getChessByPos(x, y);
                    if (chess != null) { //否则遇到棋子阻碍就得停下
                        skip++;
                        if (skip > canJump) {
                            break;
                        }
                        continue;
                    }
                    if (skip >= mustJump) {
                        rangeIndex.add(room.getIndex(x, y));
                    }
                }
            }
            return rangeIndex;
        }

        //根据规则搜索棋子默认的吃子范围
        protected List<Integer> defEatRange(int[][] dxdys, int distance) {
            return defEatRange(dxdys, distance, 0, 0);
        }

        //根据规则搜索棋子默认的吃子范围
        protected List<Integer> defEatRange(int[][] dxdys, int distance, int canJump, int mustJump) {
            List<Integer> rangeIndex = new ArrayList<>();
            for (int[] dxdy : dxdys) {
                int skip = 0;
                for (int x = row + dxdy[0], y = col + dxdy[1], i = 0; x >= 0 && x < room.curGrids.length && y >= 0 && y < room.curGrids[0].length && i < distance; x += dxdy[0], y += dxdy[1], i++) {
                    Chess chess = room.getChessByPos(x, y);
                    if (chess instanceof General) {
                        if (chess.side != this.side && skip >= mustJump) {
                            rangeIndex.add(room.getIndex(x, y));
                        }
                        skip++;
                        if (skip > canJump) {
                            break;
                        }
                    }
                }
            }
            return rangeIndex;
        }

        //根据规则搜索棋子默认的传送台范围
        protected List<Integer> defTransferRange(int[][] dxdys, int distance) {
            return defTransferRange(dxdys, distance, 0, 0);
        }

        //根据规则搜索棋子默认的传送台范围
        protected List<Integer> defTransferRange(int[][] dxdys, int distance, int canJump, int mustJump) {
            List<Integer> rangeIndex = new ArrayList<>();
            for (int[] dxdy : dxdys) {
                int skip = 0;
                for (int x = row + dxdy[0], y = col + dxdy[1], i = 0; x >= 0 && x < room.curGrids.length && y >= 0 && y < room.curGrids[0].length && i < distance; x += dxdy[0], y += dxdy[1], i++) {
                    Chess chess = room.getChessByPos(x, y);
                    if (chess != null) {
                        //公共棋子和允许传入的棋子才能选中传入底座
                        if (chess.side == 0 && room.checkAfferentAble(chess) && skip >= mustJump) {
                            rangeIndex.add(room.getIndex(x, y));
                        }
                        skip++;
                        if (skip > canJump) {
                            break;
                        }
                    }
                }
            }
            return rangeIndex;
        }

        //根据规则搜索棋子默认的可传入空格范围
        protected List<Integer> defAfferentRange(Chess choose, int[][] dxdys, int distance) {
            return defAfferentRange(choose, dxdys, distance, 0, 0);
        }

        //根据规则搜索棋子默认的可传入空格范围
        protected List<Integer> defAfferentRange(Chess choose, int[][] dxdys, int distance, int canJump, int mustJump) {
            List<Integer> rangeIndex = new ArrayList<>();
            for (int[] dxdy : dxdys) {
                int skip = 0;
                for (int x = row + dxdy[0], y = col + dxdy[1], i = 0; x >= 0 && x < room.curGrids.length && y >= 0 && y < room.curGrids[0].length && i < distance; x += dxdy[0], y += dxdy[1], i++) {
                    Chess chess = room.getChessByPos(x, y);
                    if (chess != null) { //否则遇到棋子阻碍就得停下
                        skip++;
                        if (skip > canJump) {
                            if (room.checkAfferentAble(chess)){
                                rangeIndex.add(room.getIndex(x, y)); //可传入的棋子则可以传入
                            }
                            break;
                        }
                        continue;
                    }
                    if (skip >= mustJump) {
                        if (x != choose.row || y != choose.col){ //选中棋子原来位置不能传入 (chessList上确实没有所以棋盘上这里是空位置，但是choose上自身记录的位置还是这里)
                            rangeIndex.add(room.getIndex(x, y));
                        }
                    }
                }
            }
            return rangeIndex;
        }

        /**
         * 自定义 获取可移动空格范围
         */
        public abstract List<Integer> getMoveRange();

        /**
         * 自定义 获取可吃棋子范围
         */
        public List<Integer> getEatRange(){
            return new ArrayList<>();
        }

        /**
         * 自定义 获取可选传送台棋子范围
         */
        public List<Integer> getTransferRange(){
            return new ArrayList<>();
        }

        /**
         * 自定义 获取可传入空格范围
         */
        public List<Integer> getAfferentRange(Chess choose){
            return new ArrayList<>();
        }

    }

    /**
     * 王
     */
    private static class General extends Chess {
        public General(FlyKingRoom room) {
            super(room,"王");
        }

        @Override
        public List<Integer> getMoveRange() {
            List<Integer> range = defMoveRange(new int[][]{{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1},{1, -1}, {1, 0}, {1, 1}}, 1);
            return range;
        }

        @Override
        public List<Integer> getEatRange() {
            List<Integer> range = defEatRange(new int[][]{{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1},{1, -1}, {1, 0}, {1, 1}}, 1);
            return range;
        }

        @Override
        public List<Integer> getTransferRange() {
            List<Integer> range = defTransferRange(new int[][]{{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1},{1, -1}, {1, 0}, {1, 1}}, 1);
            return range;
        }

    }

    /**
     * 士
     */
    private static class Guard extends Chess {
        public Guard(FlyKingRoom room) {
            super(room,"士");
        }

        @Override
        public List<Integer> getMoveRange() {
            return defMoveRange(new int[][]{{1, 1}, {-1, 1}, {-1, -1}, {1, -1}}, 1);
        }

        @Override
        public List<Integer> getAfferentRange(Chess choose) {
            return defAfferentRange(choose,new int[][]{{1, 1}, {-1, 1}, {-1, -1}, {1, -1}}, 1);
        }
    }

    /**
     * 象
     */
    private static class Bishop extends Chess {
        public Bishop(FlyKingRoom room) {
            super(room, "象");
        }

        @Override
        public List<Integer> getMoveRange() {
            return defMoveRange(new int[][]{{1, 1}, {-1, 1}, {-1, -1}, {1, -1}}, Integer.MAX_VALUE);
        }

        @Override
        public List<Integer> getAfferentRange(Chess choose) {
            return defAfferentRange(choose,new int[][]{{1, 1}, {-1, 1}, {-1, -1}, {1, -1}}, Integer.MAX_VALUE);
        }
    }

    /**
     * 车
     */
    private static class Chariot extends Chess {
        public Chariot(FlyKingRoom room) {
            super(room,"车");
        }

        @Override
        public List<Integer> getMoveRange() {
            return defMoveRange(new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}, Integer.MAX_VALUE);
        }

        @Override
        public List<Integer> getAfferentRange(Chess choose) {
            return defAfferentRange(choose,new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}, Integer.MAX_VALUE);
        }
    }

    /**
     * 马
     */
    private static class Horse extends Chess {
        public Horse(FlyKingRoom room) {
            super(room, "马");
        }

        @Override
        public List<Integer> getMoveRange() {
            return defMoveRange(new int[][]{{2, 1}, {2, -1},{-2, 1}, {-2, -1},{1, 2}, {-1, 2},{1, -2}, {-1, -2}}, 1);
        }

        @Override
        public List<Integer> getAfferentRange(Chess choose) {
            return defAfferentRange(choose,new int[][]{{2, 1}, {2, -1},{-2, 1}, {-2, -1},{1, 2}, {-1, 2},{1, -2}, {-1, -2}}, 1);
        }
    }

    /**
     * 炮
     */
    private static class Cannon extends Chess {
        public Cannon(FlyKingRoom room) {
            super(room,"炮");
        }

        @Override
        public List<Integer> getMoveRange() {
            return defMoveRange(new int[][]{{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1},{1, -1}, {1, 0}, {1, 1}}, Integer.MAX_VALUE, 1, 1);
        }

        @Override
        public List<Integer> getAfferentRange(Chess choose) {
            return defAfferentRange(choose,new int[][]{{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1},{1, -1}, {1, 0}, {1, 1}}, Integer.MAX_VALUE, 1, 1);
        }
    }

    /**
     * 兵
     */
    private static class Pawn extends Chess {
        public Pawn(FlyKingRoom room) {
            super(room,"兵");
        }

        @Override
        public List<Integer> getMoveRange() {
            return defMoveRange(new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}, 1);
        }

        @Override
        public List<Integer> getAfferentRange(Chess choose) {
            return defAfferentRange(choose,new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}, 1);
        }
    }

}
